package steven.savior.report.helper.main;

import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.io.File;
import java.io.IOException;
import java.net.URL;

import javax.imageio.ImageIO;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import steven.savior.report.helper.annotation.EmptyPartNoHelper;
import steven.savior.report.helper.api.ReportHelper;
import steven.savior.report.helper.exception.ReportHelperException;
import steven.savior.report.helper.module.ReportHelperModule;
import steven.savior.report.helper.util.Constant;

import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.Key;

/**
 * @author Chan Kin Wing bestwing@gmail.com
 *
 */
public class ReportHelperMain extends JFrame implements ActionListener {
	private static final long serialVersionUID = 4254803300940492752L;

	private static Log logger = LogFactory.getLog(ReportHelperMain.class);

	private static final String APPLICATION_TITLE = "Steven Savior 1.0.0";
	private static final String APPLICATION_IMAGE = "src/main/java/steven/savior/report/helper/image/cloud.jpg";

	private static final String MENU_FILE = "File";
	private static final String MENU_FILE_OPEN = "Open...";
	private static final String MENU_HELP = "Help";
	private static final String MENU_HELP_ABOUT = "About";
	private static final Icon ICON_OPEN = new ImageIcon("src/main/java/steven/savior/report/helper/image/open.jpg");
	private static final Icon ICON_SAVE = new ImageIcon("src/main/java/steven/savior/report/helper/image/save.jpg");

	private JMenuBar menuBar;
	private JMenuItem openItem;
	private JMenuItem aboutItem;
	private JTextField tfSrcFile;
	private JTextField tfTargetFile;
	private JTextArea taLog;
	private JButton btnSrcFile;
	private JButton btnTargetFile;
	private JButton btnProcess;
	private JPanel mainPanel;
	private JPanel filePanel;
	private JFileChooser fileChooser;
	private JCheckBox cbOverwrite;
	private JProgressBar progressBar;

	private File srcFile;
	private File targetFile;

	private JMenuBar getMainMenuBar() {
		menuBar = new JMenuBar();
		menuBar.add(getFileMenu());
		menuBar.add(getHelpMenu());
		return menuBar;
	}

	private JMenu getFileMenu() {
		JMenu fileMenu = new JMenu(MENU_FILE);
		fileMenu.setMnemonic(KeyEvent.VK_F);

		openItem = new JMenuItem(MENU_FILE_OPEN, ICON_OPEN);
		openItem.setMnemonic(KeyEvent.VK_O);
		openItem.addActionListener(this);

		fileMenu.add(openItem);
		return fileMenu;
	}

	private JMenu getHelpMenu() {
		JMenu helpMenu = new JMenu(MENU_HELP);
		helpMenu.setMnemonic(KeyEvent.VK_H);

		aboutItem = new JMenuItem(MENU_HELP_ABOUT);
		aboutItem.setMnemonic(KeyEvent.VK_A);
		aboutItem.addActionListener(this);

		helpMenu.add(aboutItem);
		return helpMenu;
	}

	private JButton getSrcFileBtn() {
		btnSrcFile = new JButton("Open Report...", ICON_OPEN);
		btnSrcFile.addActionListener(this);
		return btnSrcFile;
	}

	private JButton getTargetFileBtn() {
		btnTargetFile = new JButton("Save Output as...", ICON_SAVE);
		btnTargetFile.addActionListener(this);
		return btnTargetFile;
	}

	private JTextField getSrcFileTextField() {
		tfSrcFile = new JTextField();
		tfSrcFile.setEditable(false);
		return tfSrcFile;
	}

	private JTextField getTargetFileTextField() {
		tfTargetFile = new JTextField();
		tfTargetFile.setEditable(false);
		return tfTargetFile;
	}

	private JTextArea getLogTextArea() {
		taLog = new JTextArea("Steven Savior is started.");
		taLog.setEditable(false);
		return taLog;
	}

	private JCheckBox getOverwriteCheckBox() {
		cbOverwrite = new JCheckBox("Overwrite the same file");
		cbOverwrite.addActionListener(this);
		return cbOverwrite;
	}

	private JButton getProcessBtn() {
		btnProcess = new JButton("Process");
		btnProcess.addActionListener(this);
		return btnProcess;
	}

	private JFileChooser getFileChooser() {
		fileChooser = new JFileChooser();
		fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
		return fileChooser;
	}

	private JProgressBar getFileProgressBar() {
		progressBar = new JProgressBar(0, 100);
		return progressBar;
	}

	private JPanel getFilePanel() {
		filePanel = new JPanel();
		filePanel.setLayout(new GridLayout(0, 1));
		// source
		JPanel srcPanel = new JPanel(new BorderLayout());
		srcPanel.add(getSrcFileTextField(), BorderLayout.NORTH);
		JPanel srcBtnPanel = new JPanel(new FlowLayout());
		srcBtnPanel.add(getSrcFileBtn());
		srcBtnPanel.add(getOverwriteCheckBox());
		srcPanel.add(srcBtnPanel, BorderLayout.SOUTH);
		filePanel.add(srcPanel);
		// target
		JPanel targetPanel = new JPanel(new BorderLayout());
		targetPanel.add(getTargetFileTextField(), BorderLayout.NORTH);
		JPanel targetBtnPanel = new JPanel(new FlowLayout());
		targetBtnPanel.add(getTargetFileBtn());
		targetPanel.add(targetBtnPanel, BorderLayout.SOUTH);
		filePanel.add(targetPanel);
		// process
		JPanel processPanel = new JPanel(new FlowLayout());
		processPanel.add(getProcessBtn());
		filePanel.add(processPanel);
		filePanel.add(getLogTextArea());
		return filePanel;
	}

	private JPanel getMainPanel() {
		mainPanel = new JPanel();
		mainPanel.setLayout(new BorderLayout());
		mainPanel.add(getMainMenuBar(), BorderLayout.NORTH);
		mainPanel.add(getFilePanel(), BorderLayout.CENTER);
		mainPanel.add(getFileProgressBar(), BorderLayout.SOUTH);
		return mainPanel;
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		if (e.getSource() == btnSrcFile || e.getSource() == openItem) {
			setSrcFile();
		} else if (e.getSource() == btnTargetFile) {
			setTargetFile();
		} else if (e.getSource() == btnProcess) {
			process();
		} else if (e.getSource() == aboutItem) {
			showAboutMsg();
		} else if (e.getSource() == cbOverwrite) {
			setOverwriteSameFile();
		}
	}

	private void setSrcFile() {
		fileChooser = getFileChooser();
		int returnVal = fileChooser.showOpenDialog(ReportHelperMain.this);
		if (returnVal == JFileChooser.APPROVE_OPTION) {
			srcFile = fileChooser.getSelectedFile();
			tfSrcFile.setText(srcFile.getAbsolutePath());
			taLog.append("\n" + srcFile.getAbsolutePath() + " loaded.");
		}
	}

	private void setTargetFile() {
		fileChooser = getFileChooser();
		int returnVal = fileChooser.showOpenDialog(ReportHelperMain.this);
		if (returnVal == JFileChooser.APPROVE_OPTION) {
			targetFile = fileChooser.getSelectedFile();
			tfTargetFile.setText(targetFile.getAbsolutePath());
			taLog.append("\n" + targetFile.getAbsolutePath() + " loaded.");
		}
	}

	private void setOverwriteSameFile() {
		btnTargetFile.setEnabled(!cbOverwrite.isSelected());
		if (srcFile != null) {
			targetFile = srcFile;
			tfTargetFile.setText(srcFile.getAbsolutePath());
		}
	}

	private void process() {
		if (srcFile != null && targetFile != null) {
			Injector injector = Guice.createInjector(new ReportHelperModule());
			ReportHelper reportHelper = injector.getInstance(Key.get(ReportHelper.class, EmptyPartNoHelper.class));
			try {
				reportHelper.process(srcFile.getAbsolutePath(), targetFile.getAbsolutePath());
			} catch (ReportHelperException e) {
				taLog.append("\n Process failed: " + e.getMessage());
			}
			taLog.append("\n" + "Process successed.");
			progressBar.setValue(100);
		} else {
			JOptionPane.showMessageDialog(this, "Please choose source and target file.", "Error",
					JOptionPane.ERROR_MESSAGE);
		}
	}

	private void showAboutMsg() {
		StringBuilder msg = new StringBuilder();
		msg.append("Version").append(" : ").append(Constant.VERSION);
		msg.append("\n").append("Author").append(" : ").append(Constant.AUTHOR_NAME);
		msg.append("\n").append("Email").append(" : ").append(Constant.AUTHOR_EMAIL);
		JOptionPane.showMessageDialog(this, msg.toString(), APPLICATION_TITLE, JOptionPane.INFORMATION_MESSAGE,
				new ImageIcon(APPLICATION_IMAGE));
	}

	private void createAndShowGUI() {
		this.setTitle(APPLICATION_TITLE);
		try {
			this.setIconImage(ImageIO.read(new File(APPLICATION_IMAGE)));
		} catch (IOException e) {
			logger.error(e.getMessage());
		}
		this.setSize(600, 400);
		this.setResizable(true);
		this.setContentPane(getMainPanel());
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		this.setVisible(true);
	}

	public ReportHelperMain() {
		createAndShowGUI();
	}

	public static void main(String[] args) {
		// Schedule a job for the event-dispatching thread:
		// creating and showing this application's GUI.
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				new ReportHelperMain();
			}
		});
	}

	/**
	 * @param path
	 *            the image path
	 * @return Returns an ImageIcon, or null if the path was invalid.
	 */
	protected static ImageIcon createImageIcon(String path) {
		URL imgURL = ReportHelperMain.class.getResource(path);
		if (imgURL != null) {
			return new ImageIcon(imgURL);
		} else {
			logger.error("Couldn't find file: " + path);
			return null;
		}
	}
}
